#include <easyx.h>   //引用新版图形库头文件
#include <iostream> 
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string>

using namespace std;

class Expression
{
public:
    Expression(string str); //构造函数
    ~Expression(); //析构函数
    void Compute(); //计算表达式str的值
    void change();   //将中缀表达式修改为后缀表达式
    int zerowarning();   //输出除数为零警告 
 //   int fuwarning();   //输出负数阶乘警告 
private:
    int Comp(char str1, char str2); //比较str1的str2优先级
    string str;
};

Expression::Expression(string str) //接收键盘输入并加上定界符
{
    this->str = str + "#";
}

Expression :: ~Expression()
{

}

double Factor(double n)   //求阶乘 
{
    int result = 1;
    for (int i = 1; i <= n; ++i)
    {
        result *= i;
    }
    return result;
}

int Expression::zerowarning()   //除数为零警告 
{
    int zerowrong = 0;

    double OPND[100];   //存数字 
    char OPTR[100];   //存运算符 //定义两个顺序栈 

    char Unkown = '0';   //未知参数初始化为0 

    char ex[100];   //定义字符串数组用于存放转换后的数字串 
    ex[0] = '$';

    OPTR[0] = '#'; //栈OPTR初始化为定界符
    int top1 = -1, top2 = 0; //初始化栈OPND和OPTR的栈顶指针
    int i, k, op, j = 0;
    double x, y, z;

    for (i = 0; str[i] != '\0'; ) //依次扫描每一个字符
    {
        while (str[i] >= 48 && str[i] <= 57 || str[i] == '.' || str[i] == 'E' || str[i] == 'e') //数字0的ASCII码是48或是小数点(46) 
        {
            ex[j] = str[i];
            i++;
            j++;
            ex[j] = '\0';   //为了标识末尾，好判断数组ex已到末尾 ,一定要写j，若是j+1就会多出一位，使得数字有残余 
        }
        if (ex[0] != '$')
        {
            OPND[++top1] = atof(ex);
            j = 0;
            ex[0] = '$';
        }
        else if (str[i] >= 'a' && str[i] <= 'z' || str[i] >= 'A' && str[i] <= 'Z')   //判断表达式中是否含有未知量字母 (条件必须按此形式写不然报错)
        {
            Unkown = str[i];
            i++;   //继续扫描下一个 
        }
        else   //剩下的运算符情况 
        {
            k = Comp(str[i], OPTR[top2]);
            if (k == 1) //str[i]的优先级高
            {
                OPTR[++top2] = str[i++]; //将str[i]压入运算符栈
            }
            else if (k == -1) //str[i]的优先级低
            {
                y = OPND[top1--]; //从运算对象栈出栈两个元素
                x = OPND[top1--];
                op = OPTR[top2--]; //从运算符栈出栈一个元素

                switch (op) // op为运算符，进行相应运算
                {
                case '+': z = x + y; break;
                case '-': z = x - y; break;
                case '*': z = x * y; break;
                case '/':
                    if (y != 0)
                    {
                        z = x / y;
                    }
                    else
                    {
                        zerowrong = 1;
                    }
                    break;
                case '%': z = fmod(x, y); break;
                case '^':
                    z = 1;
                    for (int i = 0; i < y; i++)
                    {
                        z = z * x;
                    }
                    break;
                default: break;
                }
                OPND[++top1] = z; //运算结果入运算对象栈
            }
            else
            { //str[i]与运算符栈的栈顶元素优先级相同
                top2--; //匹配str[i]，扫描下一个字符
                i++;
            }
        }
    }
    return zerowrong;
}

void Expression::change()  //转化为后缀表达式 
{
    char character[100];   //用于存放后缀表达式中的字符 
    character[0] = '#'; //栈character初始化为定界符
    char Unkown = '0';
    int a2 = 0;   //初始化栈character的栈顶指针

    char ex[100];   //定义字符串数组用于存放转换后的数字串 
    ex[0] = '$';
    int i, j = 0;

    for (i = 0; str[i] != '\0'; ) //依次扫描每一个字符
    {
        while (str[i] >= 48 && str[i] <= 57 || str[i] == '.' || str[i] == 'E' || str[i] == 'e') //数字0的ASCII码是48或是小数点(46) 
        {
            ex[j] = str[i];
            i++;
            j++;
            ex[j] = '\0';   //为了标识末尾，好判断数组ex已到末尾 ,一定要写j，若是j+1就会多出一位，使得数字有残余 
        }
        if (str[i] >= 'a' && str[i] <= 'z' || str[i] >= 'A' && str[i] <= 'Z')
        {
            Unkown = str[i];
            i++;
        }
        if (ex[0] != '$')
        {
            double digital = atof(ex);
            j = 0;
            ex[0] = '$';
            if (Unkown != '0')   //有未知量字母 
            {
                cout << digital << Unkown << ' ';
            }
            else
            {
                cout << digital << ' ';
            }
        }
        else if (str[i] == '^' || str[i] == '!' || str[i] == '*' || str[i] == '/' || str[i] == '+' || str[i] == '-' || str[i] == '%' || str[i] == '#')
        {
            int k = Comp(str[i], character[a2]);
            if (k == 1) //str[i]的优先级高
            {
                character[++a2] = str[i++]; //将str[i]压入运算符栈
            }
            else if (k == -1) //str[i]的优先级低
            {
                while (Comp(str[i], character[a2]) == -1)
                {
                    cout << character[a2] << ' ';   //输出顶端的操作符 
                    character[a2--];   //导出顶端操作符 
                }
                character[++a2] = str[i++];
            }
        }
        else if (str[i] == '(')    //扫描到左括号的情况 
        {
            character[++a2] = str[i++]; //将str[i]压入运算符栈
        }
        else if (str[i] == ')')   //扫描到右括号的情况 
        {
            while (character[a2] != '(')   //判断目前栈顶元素是否为左括号 
            {
                cout << character[a2] << ' ';   //输出顶端的操作符 
                character[a2--];   //导出顶端操作符 
            }
            character[a2--];   //将左括号移除
            i++;   //继续扫描下一个 
        }
    }
    cout << endl;
}
void Expression::Compute()
{
    double OPND[100];   //存数字 
    char OPTR[100];   //存运算符 //定义两个顺序栈 

    char Unkown = '0';   //未知参数初始化为0 

    char ex[100];   //定义字符串数组用于存放转换后的数字串 
    ex[0] = '$';

    OPTR[0] = '#'; //栈OPTR初始化为定界符
    int top1 = -1, top2 = 0; //初始化栈OPND和OPTR的栈顶指针
    int i, k, op, j = 0;
    double x, y, z = 0;

    for (i = 0; str[i] != '\0'; ) //依次扫描每一个字符
    {
        while (str[i] >= 48 && str[i] <= 57 || str[i] == '.' || str[i] == 'E' || str[i] == 'e') //数字0的ASCII码是48或是小数点(46) 
        {
            ex[j] = str[i];
            i++;
            j++;
            ex[j] = '\0';   //为了标识末尾，好判断数组ex已到末尾 ,一定要写j，若是j+1就会多出一位，使得数字有残余 
        }
        if (ex[0] != '$')
        {
            OPND[++top1] = atof(ex);
            j = 0;
            ex[0] = '$';
        }
        else if (str[i] >= 'a' && str[i] <= 'z' || str[i] >= 'A' && str[i] <= 'Z')   //判断表达式中是否含有未知量字母 (条件必须按此形式写不然报错)
        {
            Unkown = str[i];
            i++;   //继续扫描下一个 
        }
        else if (str[i] == '!')   //单独计算阶乘 
        {
            if (x >= 0)
            {
                x = OPND[top1--]; //从运算对象栈出栈一个元素
                z = Factor(x);   //求阶乘的函数 
                OPND[++top1] = z; //运算结果入运算对象栈

                i++;
            }
            else
            {
                cout << "负数没有阶乘！！！";
            }
        }
        else   //剩下的运算符情况 
        {
            k = Comp(str[i], OPTR[top2]);
            if (k == 1) //str[i]的优先级高
            {
                OPTR[++top2] = str[i++]; //将str[i]压入运算符栈
            }
            else if (k == -1) //str[i]的优先级低
            {
                y = OPND[top1--]; //从运算对象栈出栈两个元素
                x = OPND[top1--];
                op = OPTR[top2--]; //从运算符栈出栈一个元素

                switch (op) // op为运算符，进行相应运算
                {
                case '+': z = x + y; break;
                case '-':
                    z = x - y; break;
                case '*': z = x * y; break;
                case '/':
                    if (y != 0)
                    {
                        z = x / y;
                    }
                    else
                    {
                        cout << "除数不能为零！！！";
                    }
                    break;
                case '%': z = fmod(x, y); break;
                case '^':
                    z = 1;
                    for (int i = 0; i < y; i++)
                    {
                        z = z * x;
                    }
                    break;
                default: break;
                }
                OPND[++top1] = z; //运算结果入运算对象栈
            }
            else
            { //str[i]与运算符栈的栈顶元素优先级相同
                top2--; //匹配str[i]，扫描下一个字符
                i++;
            }
        }
    }
    if (Unkown != '0')   //表达式中有字符 
    {
        if (OPND[top1] == 0)   //但最终结果为0，则直接输出0
        {
            cout << OPND[top1] << endl;
        }
        else
        {
            cout << OPND[top1] << Unkown << endl;
        }
    }
    else   //表达式中没有字符 
    {
        cout << OPND[top1] << endl; //运算对象栈的栈顶元素即为运算结果
    }
}

int Expression::Comp(char str1, char str2)
{ //比较str1和str2的优先级，1：str1高；0：相同；-1：str1低
    switch (str1)
    {
    case '+': case '-': if (str2 == '(' || str2 == '#') return 1; else return -1;
        break;
    case '*': case '/':case '%':if (str2 == '(' || str2 == '#' || str2 == '+' || str2 == '-') return 1; else return -1;
        break;
    case '^':case '!':if (str2 == '^' || str2 == '!') return -1; else return 1;
    case '(': return 1; break;
    case ')': if (str2 == '(') return 0; else return -1;
        break;
    case '#': if (str2 == '#') return 0; else return -1;
        break;
    default: break;
    }
}

void dengyu_button(int x, int y, int w, int h)
{
    setbkmode(TRANSPARENT);   //文字的背景颜色与按钮颜色相同
    setfillcolor(BROWN);   //填充按钮颜色
    fillroundrect(x, y, x + w, y + h, 10, 10);    //设置矩形曲率
    outtextxy(x, y, "=");   //把要求的文字输出到按钮上
}

void jiahao_button(int x, int y, int w, int h)
{
    setbkmode(TRANSPARENT);   //文字的背景颜色与按钮颜色相同
    setfillcolor(BROWN);   //填充按钮颜色
    fillroundrect(x, y, x + w, y + h, 10, 10);    //设置矩形曲率
    outtextxy(x, y, "+");   //把要求的文字输出到按钮上
}

int main()
{
  /*  string str;
    int count = 0;
    int wrong1 = 0;   //判断除数 
//	int wrong2=0;   //判断阶乘负数 
*/
    //图形界面
    initgraph(640, 480,EW_SHOWCONSOLE);   //初始化绘图环境
    dengyu_button(50, 50, 150, 50);
    jiahao_button(50, 100, 150, 50);
    getchar();   //getchar缓存输入函数，从键盘输入多个字符时；将所有字符保存在键盘缓存区，直到遇到回车。
/*
    while (1)
    {
        cout << "请输入一个表达式：" << endl;
        cin >> str;

        Expression E{ str }; //定义对象变量E

        wrong1 = E.zerowarning();
        //	wrong2=E.fuwarning();
        if (wrong1 == 0)
        {
            cout << "表达式的值是：" << endl;   //方法直接输出结果
            E.Compute();   //方法直接输出结果
            cout << "其后缀表达式为：" << endl;
            E.change();  //调用输出后缀表达式的方法 
        }
        else if (wrong1 == 1)
        {
            cout << "除数不能为0！！！" << endl;
        }
        /*		else if(wrong2==1&&wrong1==0)
                {
                    cout<<"负数没有阶乘！！！"<<endl;
                }
                else if(wrong1==1&&wrong2==1)
                {
                    cout<<"除数不能为0！！！"<<endl;
                    cout<<"负数没有阶乘！！！"<<endl;
                }*/
  //}
    return 0;
}